#ifndef MESSAGE_QUEUE_H_
#define MESSAGE_QUEUE_H_

#include "MessageQueueException.h"

#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <string>

/**
 * Clase que implementa una cola de mensajes genérica
 *
 * Los métodos arrojan la excepción MessageQueueException en caso de fallar.
 *
 */
template <class T> class MessageQueue {

private:
		key_t	clave;
		int		id;
public:
		MessageQueue ();

		~MessageQueue();

		int open(std::string fileName,char letra);

		int send ( T *dato );

		int receive ( int tipo,T* buffer );

		void removeQueue();
};

template <class T> MessageQueue<T> :: MessageQueue () {
	clave = -1;
	id = -1;
}

template <class T> MessageQueue<T> :: ~MessageQueue () {

}

template <class T> int MessageQueue<T> :: open(std::string fileName,char letra) {

	this->clave = ftok ( fileName.c_str(),letra );
	if ( this->clave == -1 ) {
		perror ( "Error en ftok" );

		MessageQueueException e;
		throw e;

	}

	this->id = msgget ( this->clave, 0660 | IPC_CREAT );
	if ( this->id == -1 ) {
		perror ( "Error en msgget" );

		MessageQueueException e;
		throw e;
	}

	return this->id;
}

template <class T> int MessageQueue<T> :: send ( T *dato ) {
	int result = -1;
	if ( dato != NULL ) {
		result = msgsnd ( this->id,(const void *)dato,sizeof(T)-sizeof(long),0 );
		if ( result == -1 )	{
			MessageQueueException e;
			throw e;
		}
	}
	return result;
}

template <class T> int MessageQueue<T> :: receive ( int tipo,T* buffer ) {
	int result = -1;
	if ( buffer != NULL ) {
		result = msgrcv ( this->id,(void *)buffer,sizeof(T)-sizeof(long),tipo,0 );
		if ( result == -1 ) {
			MessageQueueException e;
			throw e;
		}
	}
	return result;
}

template <class T> void MessageQueue<T>::removeQueue() {
	msgctl ( this->id,IPC_RMID,NULL );
}

#endif
